Помогите пользователям с одноразовыми паролями, полученными по SMS
Что такое API WebOTP?
В наши дни большинство людей в мире владеют мобильными устройствами, и разработчики часто используют номера телефонов в качестве идентификатора пользователей своих сервисов.
Существует множество способов проверки телефонных номеров, но одним из самых распространенных является случайно сгенерированный одноразовый пароль (OTP), отправляемый по SMS. Отправка этого кода обратно на сервер разработчика демонстрирует контроль над телефонным номером.
Эта идея уже применяется во многих сценариях для достижения следующих целей:
- Номер телефона как идентификатор пользователя. При регистрации на новую услугу некоторые веб-сайты запрашивают номер телефона вместо адреса электронной почты и используют его как идентификатор учетной записи.
- Двухэтапная аутентификация. При входе в систему веб-сайт запрашивает одноразовый код, отправленный по SMS, в дополнение к паролю или другому фактору знания для дополнительной безопасности.
- Подтверждение платежа. Когда пользователь совершает платеж, запрос одноразового кода, отправленного по SMS, может помочь проверить намерения человека.
Текущий процесс создает трудности для пользователей. Поиск одноразового пароля в SMS-сообщении, а затем его копирование и вставка в форму — это обременительно, что снижает показатели конверсии в критических пользовательских путешествиях. Упрощение этого процесса было давним запросом для веба от многих крупнейших мировых разработчиков. У Android есть API, который делает именно это . То же самое делают iOS и Safari .
API WebOTP позволяет вашему приложению получать специально отформатированные сообщения, привязанные к домену вашего приложения. Благодаря этому вы можете программно получить OTP из SMS-сообщения и проще проверить номер телефона пользователя.
Посмотрите на это в действии
Допустим, пользователь хочет подтвердить свой номер телефона на веб-сайте. Веб-сайт отправляет пользователю текстовое сообщение по SMS, и пользователь вводит одноразовый пароль из сообщения, чтобы подтвердить право собственности на номер телефона.
С API WebOTP эти шаги для пользователя так же просты, как одно нажатие, как показано в видео. Когда приходит текстовое сообщение, всплывает нижний лист и предлагает пользователю подтвердить свой номер телефона. После нажатия кнопки «Проверить» на нижнем листе браузер вставляет OTP в форму, и форма отправляется без необходимости нажатия пользователем «Продолжить» .
Весь процесс схематически изображен на рисунке ниже.

Попробуйте демо сами. Он не запрашивает ваш номер телефона и не отправляет SMS на ваше устройство, но вы можете отправить его с другого устройства, скопировав текст, отображаемый в демо. Это работает, потому что неважно, кто отправитель при использовании API WebOTP.
- Перейдите по адресу https://web-otp.glitch.me в Chrome 84 или более поздней версии на устройстве Android.
- Отправьте на свой телефон следующее текстовое SMS-сообщение с другого телефона.
Your OTP is: 123456.
@web-otp.glitch.me #123456
Вы получили SMS и увидели приглашение ввести код в поле ввода? Так работает API WebOTP для пользователей.
Использование API WebOTP состоит из трех частей:
- Правильно аннотированный тег
<input>
- JavaScript в вашем веб-приложении
- Форматированный текст сообщения, отправленного по SMS.
Сначала я расскажу о теге <input>
.
Аннотируйте тег <input>
Сам по себе WebOTP работает без каких-либо HTML-аннотаций, но для кроссбраузерной совместимости я настоятельно рекомендую вам добавить autocomplete="one-time-code"
в тег <input>
там, где вы ожидаете, что пользователь введет одноразовый пароль.
Это позволяет Safari 14 или более поздней версии предлагать пользователю автоматически заполнить поле <input>
одноразовым паролем при получении SMS-сообщения в формате, описанном в разделе Форматирование SMS-сообщения, даже если оно не поддерживает WebOTP.
HTML
<form>
<input autocomplete="one-time-code" required/>
<input type="submit">
</form>
Используйте API WebOTP
Поскольку WebOTP прост, просто скопируйте и вставьте следующий код, и все будет готово. Я в любом случае покажу вам, что происходит.
JavaScript
if ('OTPCredential' in window) {
window.addEventListener('DOMContentLoaded', e => {
const input = document.querySelector('input[autocomplete="one-time-code"]');
if (!input) return;
const ac = new AbortController();
const form = input.closest('form');
if (form) {
form.addEventListener('submit', e => {
ac.abort();
});
}
navigator.credentials.get({
otp: { transport:['sms'] },
signal: ac.signal
}).then(otp => {
input.value = otp.code;
if (form) form.submit();
}).catch(err => {
console.log(err);
});
});
}
Обнаружение особенностей
Обнаружение функций такое же, как и для многих других API. Прослушивание события DOMContentLoaded
будет ожидать готовности дерева DOM к запросу.
JavaScript
if ('OTPCredential' in window) {
window.addEventListener('DOMContentLoaded', e => {
const input = document.querySelector('input[autocomplete="one-time-code"]');
if (!input) return;
…
const form = input.closest('form');
…
});
}
Обработать OTP
API WebOTP сам по себе достаточно прост. Используйте navigator.credentials.get()
для получения OTP. WebOTP добавляет новую опцию otp
к этому методу. У него есть только одно свойство: transport
, значение которого должно быть массивом со строкой 'sms'
.
JavaScript
…
navigator.credentials.get({
otp: { transport:['sms'] }
…
}).then(otp => {
…
Это запускает поток разрешений браузера при получении SMS-сообщения. Если разрешение предоставлено, возвращаемое обещание разрешается с объектом OTPCredential
.
Содержание полученного объекта OTPCredential
{
code: "123456" // Obtained OTP
type: "otp" // `type` is always "otp"
}
Затем передайте значение OTP в поле <input>
. Отправка формы напрямую устранит шаг, требующий от пользователя нажатия кнопки.
JavaScript
…
navigator.credentials.get({
otp: { transport:['sms'] }
…
}).then(otp => {
input.value = otp.code;
if (form) form.submit();
}).catch(err => {
console.error(err);
});
…
Отмена сообщения
В случае, если пользователь вручную вводит одноразовый пароль и отправляет форму, вы можете отменить вызов get()
, используя экземпляр AbortController
в объекте options
.
JavaScript
…
const ac = new AbortController();
…
if (form) {
form.addEventListener('submit', e => {
ac.abort();
});
}
…
navigator.credentials.get({
otp: { transport:['sms'] },
signal: ac.signal
}).then(otp => {
…
Форматировать SMS-сообщение
API сам по себе должен выглядеть достаточно просто, но есть несколько вещей, которые вы должны знать перед его использованием. Сообщение должно быть отправлено после вызова navigator.credentials.get()
и должно быть получено на устройстве, где был вызван get()
. Наконец, сообщение должно соответствовать следующему форматированию:
- Сообщение начинается с удобочитаемого текста, содержащего строку из четырех-десяти буквенно-цифровых символов, включающую как минимум одну цифру, а последняя строка — URL-адрес и одноразовый пароль.
- Доменная часть URL-адреса веб-сайта, вызвавшего API, должна начинаться с символа
@
. - URL-адрес должен содержать знак решетки ('
#
'), за которым следует одноразовый пароль.
Например:
Your OTP is: 123456.
@www.example.com #123456
Вот плохие примеры:
Пример неправильно сформированного текста SMS | Почему это не сработает |
---|---|
Here is your code for @example.com #123456 | Ожидается, что @ будет первым символом последней строки. |
Your code for @example.com is #123456 | Ожидается, что @ будет первым символом последней строки. |
Your verification code is 123456 @example.com\t#123456 | Между @host и #code ожидается один пробел. |
Your verification code is 123456 @example.com #123456 | Между @host и #code ожидается один пробел. |
Your verification code is 123456 @ftp://example.com #123456 | Схема URL не может быть включена. |
Your verification code is 123456 @https://example.com #123456 | Схема URL не может быть включена. |
Your verification code is 123456 @example.com:8080 #123456 | Порт не может быть включен. |
Your verification code is 123456 @example.com/foobar #123456 | Путь не может быть включен. |
Your verification code is 123456 @example .com #123456 | В домене нет пробелов. |
Your verification code is 123456 @domain-forbiden-chars-#%/:<>?@[] #123456 | В домене нет запрещённых символов . |
@example.com #123456 Mambo Jumbo | @host и #code должны быть последней строкой. |
@example.com #123456 App hash #oudf08lkjsdf834 | @host и #code должны быть последней строкой. |
Your verification code is 123456 @example.com 123456 | Отсутствующий # . |
Your verification code is 123456 example.com #123456 | Отсутствующий @ . |
Hi mom, did you receive my last text | Отсутствуют @ и # . |
Демо-версии
Попробуйте разные сообщения с помощью демо: https://web-otp.glitch.me
Вы также можете сделать форк и создать свою версию: https://glitch.com/edit/#!/web-otp .
Используйте WebOTP из кросс-источника iframe
Ввод SMS OTP в кросс-оригинальный iframe обычно используется для подтверждения платежа, особенно с 3D Secure. Имея общий формат для поддержки кросс-оригинальных iframe, API WebOTP предоставляет OTP, привязанные к вложенным источникам. Например:
- Пользователь посещает
shop.example
, чтобы купить пару обуви с помощью кредитной карты. - После ввода номера кредитной карты интегрированный платежный провайдер отображает форму из
bank.example
в iframe, предлагающую пользователю подтвердить свой номер телефона для быстрой оплаты. -
bank.example
отправляет пользователю SMS-сообщение, содержащее одноразовый пароль, который он может ввести для подтверждения своей личности.
Чтобы использовать API WebOTP из кросс-доменного iframe, вам необходимо выполнить две вещи:
- Укажите в текстовом сообщении SMS-сообщения как начало верхнего фрейма, так и начало iframe.
- Настройте политику разрешений, чтобы разрешить кросс-источниковому iframe получать OTP от пользователя напрямую.
Вы можете попробовать демоверсию по адресу https://web-otp-iframe-demo.stackblitz.io .
Добавить примечания bound-origins к текстовому сообщению SMS
При вызове API WebOTP из iframe текстовое SMS-сообщение должно включать источник верхнего фрейма, которому предшествует @
, за которым следует OTP, которому предшествует #
и источник iframe, которому предшествует @
в последней строке.
Your verification code is 123456
@shop.example #123456 @bank.exmple
Настроить политику разрешений
Чтобы использовать WebOTP в кросс-источнике iframe, встраиваемый должен предоставить доступ к этому API через политику разрешений otp-credentials, чтобы избежать непреднамеренного поведения. В общем, есть два способа достичь этой цели:
через HTTP-заголовок:
Permissions-Policy: otp-credentials=(self "https://bank.example")
через атрибут allow
iframe:
<iframe src="https://bank.example/…" allow="otp-credentials"></iframe>
См. дополнительные примеры того, как задать политику разрешений .
Используйте WebOTP на ПК
В Chrome WebOTP поддерживает прослушивание SMS-сообщений, полученных на других устройствах, чтобы помочь пользователям выполнить проверку номера телефона на настольном компьютере.
Для использования этой возможности пользователю необходимо войти в одну и ту же учетную запись Google как в настольном Chrome, так и в Android Chrome.
Все, что нужно сделать разработчикам, — это реализовать API WebOTP на своем десктопном сайте, так же, как они это делают на своем мобильном сайте, но никаких особых ухищрений не требуется.
Более подробную информацию можно узнать в статье Проверка номера телефона на компьютере с помощью API WebOTP .
Часто задаваемые вопросы
Диалог не появляется, хотя я отправляю правильно отформатированное сообщение. Что не так?
При тестировании API необходимо учитывать несколько моментов:
- Если номер телефона отправителя включен в список контактов получателя, этот API не будет активирован из-за конструкции базового API согласия пользователя SMS .
- Если вы используете рабочий профиль на своем Android-устройстве и WebOTP не работает, попробуйте установить и использовать Chrome в своем личном профиле (т. е. в том же профиле, в котором вы получаете SMS-сообщения).
Проверьте формат еще раз, чтобы убедиться, что ваше SMS-сообщение отформатировано правильно.
Совместим ли этот API с различными браузерами?
Chromium и WebKit договорились о формате текстового сообщения SMS , а Apple объявила о его поддержке Safari, начиная с iOS 14 и macOS Big Sur. Хотя Safari не поддерживает WebOTP JavaScript API, аннотируя элемент input
с помощью autocomplete=["one-time-code"]
, клавиатура по умолчанию автоматически предлагает ввести OTP, если сообщение SMS соответствует формату.
Безопасно ли использовать SMS в качестве способа аутентификации?
Хотя SMS OTP полезен для проверки номера телефона при первом предоставлении номера, проверку номера телефона с помощью SMS следует использовать осторожно для повторной аутентификации, поскольку операторы могут перехватывать и повторно использовать номера телефонов. WebOTP — удобный механизм повторной аутентификации и восстановления, но сервисы должны сочетать его с дополнительными факторами, такими как проверка знаний, или использовать API веб-аутентификации для надежной аутентификации.
Куда я могу сообщить об ошибках в реализации Chrome?
Вы обнаружили ошибку в реализации Chrome?
- Сообщите об ошибке на crbug.com . Включите как можно больше подробностей, простые инструкции по воспроизведению и установите для компонентов значение
Blink>WebOTP
.
Как я могу помочь этой функции?
Планируете ли вы использовать API WebOTP? Ваша публичная поддержка помогает нам расставлять приоритеты в функциях и показывает другим поставщикам браузеров, насколько важно их поддерживать. Отправьте твит @ChromiumDev с хэштегом #WebOTP
и расскажите, где и как вы его используете.
Ресурсы
- Лучшие практики использования одноразовых паролей в SMS-формах
- Проверка номера телефона на компьютере с помощью WebOTP API
- Заполняйте формы OTP в кросс-источниковых iframe с помощью API WebOTP
- Беспарольная аутентификация Yahoo! JAPAN сократила количество запросов на 25%, ускорив время входа в систему в 2,6 раза